/*
 * SPDX-FileCopyrightText: 2022-2024 Andrew Gunnerson
 * SPDX-License-Identifier: GPL-3.0-only
 */

package com.sanji.audio_test.format

import android.media.MediaCodec
import android.media.MediaFormat
import java.nio.ByteBuffer

/**
 * 创建一个指定格式的直通编码器（不重新编码，直接传输原始数据）
 *
 * @param mediaFormat 由 [Format.getMediaFormat] 返回的 [MediaFormat] 实例
 * @param container 用于存储原始 PCM 音频流的容器
 */
class PassthroughEncoder(
    private val mediaFormat: MediaFormat,
    private val container: Container,
) : Encoder(mediaFormat) {
    // 标记编码器是否已启动
    private var isStarted = false
    // 用于存储媒体编解码器缓冲区信息
    private val bufferInfo = MediaCodec.BufferInfo()
    // 轨道索引，初始值为-1表示尚未添加轨道
    private var trackIndex = -1

    /**
     * 启动编码器
     * @throws IllegalStateException 如果编码器已经启动
     */
    override fun start() {
        // 检查编码器是否已经启动，如果已启动则抛出异常
        if (isStarted) {
            throw IllegalStateException("编码器已经启动")
        }

        // 设置编码器状态为已启动
        isStarted = true
        // 向容器中添加音轨并获取轨道索引
        trackIndex = container.addTrack(mediaFormat)
        // 启动容器
        container.start()
    }

    /**
     * 停止编码器
     * @throws IllegalStateException 如果编码器尚未启动
     */
    override fun stop() {
        // 检查编码器是否未启动，如果未启动则抛出异常
        if (!isStarted) {
            throw IllegalStateException("编码器尚未启动")
        }

        // 设置编码器状态为未启动
        isStarted = false
    }

    /**
     * 释放编码器资源
     * 如果编码器正在运行，则先停止它
     */
    override fun release() {
        // 如果编码器正在运行，则停止它
        if (isStarted) {
            stop()
        }
    }

    /**
     * 编码数据
     * @param buffer 包含音频数据的字节缓冲区
     * @param isEof 是否为最后一帧数据（文件结束标志）
     * @throws IllegalStateException 如果编码器尚未启动
     */
    override fun encode(buffer: ByteBuffer, isEof: Boolean) {
        // 检查编码器是否未启动，如果未启动则抛出异常
        if (!isStarted) {
            throw IllegalStateException("编码器尚未启动")
        }

        // 计算帧数：剩余字节数除以每帧大小
        val frames = buffer.remaining() / frameSize

        // 设置缓冲区信息
        bufferInfo.offset = buffer.position()  // 数据在缓冲区中的起始位置
        bufferInfo.size = buffer.limit()       // 数据大小
        bufferInfo.presentationTimeUs = timestampUs  // 显示时间戳（微秒）
        bufferInfo.flags = if (isEof) {
            // 如果是最后一帧，设置结束标志
            MediaCodec.BUFFER_FLAG_END_OF_STREAM
        } else {
            0  // 否则无特殊标志
        }

        // 将样本数据写入容器
        container.writeSamples(trackIndex, buffer, bufferInfo)

        // 更新已处理的帧数
        numFrames += frames
    }
}